package ztcp_server

import (
	"errors"
	"fmt"
	"gitee.com/zouyang8210/zconv"
	"net"
	"runtime/debug"
	"strings"
	"time"
)

func (c *TcpServer) init() {
	// 如果未设置最大连接数,则自动设置10000默认值
	if c.maxConn == 0 {
		c.maxConn = 20000
	}
	c.chConnChange = make(chan int)
	c.chIndex = make(chan int, 100)
	c.chClose = make(chan int)

	if c.connTimeout == 0 {
		c.connTimeout = 120
	}
	if c.checkInterval == 0 {
		c.checkInterval = 10
	}

	c.clientList = make([]TcpClient, c.maxConn) // 设置连接池大小

	c.checkConnect() // 连接心跳超时和登录检测
	c.monitorChan()  // 通道监测

}

// 接受连接
func (c *TcpServer) accept() {

	for {
		var e error
		var conn net.Conn
		var idx int
		if conn, e = c.listen.Accept(); e == nil {
			if idx = c.findFreeIndex(); idx < 0 {
				_ = conn.Close()
			}
			c.clientList[idx].Conn = conn
			c.clientList[idx].chLock = make(chan byte, 1)

			c.chIndex <- idx
			c.chConnChange <- +1
		}
	}
}

// 开始接收数据
func (c *TcpServer) startReceiveData(idx int) {
	defer func() {
		if r := recover(); r != nil {
			fmt.Printf("index:%d\nerror: %v\nstack:%s\n", idx, r, string(debug.Stack()))
		}
	}()
	defer func() {
		_ = c.close(idx)
	}()

	//var res = false
	var e error
	var n int
	for {
		cache := make([]byte, 4096)
		n, e = c.readDataFormat(idx, cache)
		if e != nil {
			go c.sendReadErrorEvent(c.clientList[idx].Index, c.clientList[idx].Sn, e)
			if !strings.Contains(e.Error(), IoTimeout) {
				break
			}
		}
		if n > 0 {
			go func(buf []byte, size int, cli *TcpClient) {
				c.sendReceiveEvent(buf, size, cli)
			}(cache[:n], len(cache[:n]), &c.clientList[idx])
		}
	}
}

func (c *TcpServer) readDataFormat(clientIndex int, cache []byte) (size int, e error) {
	defer func() {
		if c.clientList[clientIndex].Conn != nil {
			_ = c.clientList[clientIndex].Conn.SetReadDeadline(time.Time{})
		}
	}()

	if c.protoFormat.DataSize > 0 && !c.protoFormat.Later { // 接收固定长度的数据
		e = c.readFixedData(cache, clientIndex, &size, c.protoFormat.DataSize)
	} else if c.protoFormat.Later && c.protoFormat.DataSize > 0 { // 先接收协议头，通过协议头的数据长度来接收余下的数据
		_ = c.clientList[clientIndex].Conn.SetReadDeadline(time.Time{})
		e = c.readFixedData(cache, clientIndex, &size, c.protoFormat.DataSize)
		if e == nil {
			var dataSize uint16
			e = zconv.BytesToObject(cache[c.protoFormat.LengthIndex:c.protoFormat.LengthIndex+c.protoFormat.LengthSize], zconv.ASC, &dataSize)
			if e == nil {
				tmpOffset := 0
				_ = c.clientList[clientIndex].Conn.SetReadDeadline(time.Now().Add(1000 * time.Millisecond))
				e = c.readFixedData(cache[c.protoFormat.DataSize:], clientIndex, &tmpOffset, size)
				size += tmpOffset
			}
		}
	} else if c.protoFormat.headLen > 0 && c.protoFormat.endLen > 0 { // 接收有头,有尾的数据
		if e = c.readHeadData(cache, clientIndex, &size, c.protoFormat.headLen); e == nil {
			e = c.readToEnding(cache, clientIndex, &size, c.protoFormat.headLen, c.protoFormat.End)
		}
	} else if c.protoFormat.endLen > 0 { // 接收只有结尾符的数据
		e = c.readToEnding(cache, clientIndex, &size, c.protoFormat.headLen, c.protoFormat.End)
	} else {
		// 接收没有设置接收格式的数据或json数据
		size, e = c.readVariableData(cache, clientIndex)
	}
	if e == nil || strings.Contains(e.Error(), IoTimeout) {
		c.clientList[clientIndex].LastPackageTime = time.Now().Unix()
	}

	return size, e
}

// 读取固定长件数据
func (c *TcpServer) readFixedData(buff []byte, clientIndex int, offset *int, count int) (err error) {
	sum := 0
	tmpLen := 0
	for {
		if *offset >= count {
			break
		}
		tmpLen, err = c.readData(buff, clientIndex, *offset, count-sum)
		if tmpLen > 0 {
			*offset += tmpLen
			sum += tmpLen
		}

		if err != nil {
			break
		}
		_ = c.clientList[clientIndex].Conn.SetReadDeadline(time.Now().Add(1000 * time.Millisecond))
		time.Sleep(10 * time.Millisecond)
	}
	return
}

//读取数据
func (c *TcpServer) readData(buff []byte, clientIndex, index, size int) (count int, err error) {
	defer func() {
		if p := recover(); p != nil {
			fmt.Println(p)
			debug.PrintStack()
		}
	}()

	if len(buff) < size-index {
		return 0, errors.New("buffer cache is too small")
	}

	if c.clientList[clientIndex].Conn == nil {
		err = errors.New("connect is nil")
		return
	}

	count, err = c.clientList[clientIndex].Conn.Read(buff[index : index+size])
	return
}

// 读取协议头部信息
func (c *TcpServer) readHeadData(buff []byte, clientIndex int, offset *int, headLen int) (err error) {
	var i = 0
	for i < headLen {
		if _, e := c.readData(buff, clientIndex, i, 1); e != nil {
			err = errors.New("read header error: " + e.Error())
			break
		}
		if buff[*offset+i] == c.protoFormat.Head[i] {
			i++
		}
	}
	*offset += i
	return
}

// 是否收接到协议尾
func (c *TcpServer) endValid(buff []byte, headLen, dataSize int, end []byte) (result bool) {
	endLen := len(end)
	result = true
	if (dataSize - headLen) <= endLen {
		return false
	}
	for i := 0; i < endLen; i++ {
		if buff[dataSize-endLen+i] != end[i] {
			result = false
			break
		}
	}
	return
}

// 读取到协议尾部
func (c *TcpServer) readToEnding(buff []byte, clientIndex int, offset *int, headLen int, end []byte) (err error) {
	var tmpLen int
	for {
		if ok := c.endValid(buff, headLen, *offset, end); ok { // 没有接收到协议尾,断续接收
			break
		}
		if *offset < len(buff) {
			_ = c.clientList[clientIndex].Conn.SetReadDeadline(time.Now().Add(1000 * time.Millisecond))
			tmpLen, err = c.readData(buff, clientIndex, *offset, 1)
			if err != nil {
				err = errors.New("read protocol tail info error: " + err.Error())
				break
			}
			*offset += tmpLen
		} else {
			err = errors.New("read  protocol tail info error: data buffer out") // 数据缓存益出
			break
		}
	}
	return
}

// 接收没有固定格式且不定长的协议
func (c *TcpServer) readVariableData(buff []byte, clientIndex int) (count int, err error) {

	//count, err = c.readData(buff, clientIndex, 0, len(buff))
	if c.isJson {
		count, err = c.readData(buff, clientIndex, 0, 1)
	} else {
		count, err = c.readData(buff, clientIndex, 0, len(buff))
	}
	// 下面if语句为读取完成的json数据而定制
	if !c.isJson || err != nil || count <= 0 {
		return
	}

	for {
		left := strings.Count(string(buff), "{")
		right := strings.Count(string(buff), "}")
		if left == right && left > 0 && right > 0 {
			return
		}
		_ = c.clientList[clientIndex].Conn.SetReadDeadline(time.Now().Add(2000 * time.Millisecond))
		var n int
		n, err = c.readData(buff, clientIndex, count, 1)
		if err != nil {
			return
		}
		count += n
		if count >= len(buff) {
			fmt.Println("rec data too length:", string(buff))
			return
		}
	}
}

// 通道监测
func (c *TcpServer) monitorChan() {
	go func() {
		for {
			select {
			case idx := <-c.chIndex:
				c.clientList[idx].Index = idx
				c.clientList[idx].Addr = c.clientList[idx].Conn.RemoteAddr().String()
				c.clientList[idx].LastPackageTime = time.Now().Unix()
				c.clientList[idx].Connected = true
				c.clientList[idx].ConnectTime = time.Now().Unix()
				go c.sendConnEvent(c.clientList[idx].Addr, "", c.clientList[idx].Index, true) // 发送连接事件
				go c.startReceiveData(idx)
			case sum := <-c.chConnChange:
				c.connSum += sum
			}
		}
	}()
}

//发送连接事件
func (c *TcpServer) sendConnEvent(addr, sn string, clientIndex int, value bool) {
	if c.connCallback != nil {
		c.connCallback(addr, sn, clientIndex, value)
	}
}

//发送收到数据事件
func (c *TcpServer) sendReceiveEvent(data []byte, size int, client *TcpClient) {
	if c.dataCallback != nil {
		c.dataCallback(data, size, client)
	}
}

// 发送读取数据错误事件
func (c *TcpServer) sendReadErrorEvent(cliIndex int, cliSn string, e error) {
	if c.onReadErrorEvent != nil {
		c.onReadErrorEvent(cliIndex, cliSn, e)
	}
}

// 连接超时检测
func (c *TcpServer) checkConnect() {
	go func() {
		for {
			time.Sleep(time.Duration(c.checkInterval) * time.Second)
			if !c.checkConn {
				continue
			}
			for i := range c.clientList {
				if c.clientList[i].Conn == nil {
					continue
				}
				if sec := time.Now().Unix() - c.clientList[i].LastPackageTime; sec > c.connTimeout {
					_ = c.close(c.clientList[i].Index)
				}
				time.Sleep(50 * time.Millisecond)
			}
		}
	}()
}

// 关闭连接
func (c *TcpServer) close(index int) (err error) {
	if index < 0 || index > c.maxConn-1 {
		return errors.New("index out of range")
	}
	if c.clientList[index].Conn != nil {
		c.clientList[index].chLock <- 1
		defer func() {
			<-c.clientList[index].chLock
		}()
		_ = c.clientList[index].Conn.Close()
		addr := c.clientList[index].Addr
		c.clientList[index].Connected = false
		c.clientList[index].Conn = nil
		c.clientList[index].Addr = ""
		c.clientList[index].ErrSum = 0
		c.clientList[index].LastPackageTime = 0
		c.clientList[index].ConnectTime = 0
		c.clientList[index].Index = -1
		c.connMap.Delete(c.clientList[index].Sn)
		sn := c.clientList[index].Sn
		c.clientList[index].Sn = ""

		c.chConnChange <- -1
		go c.sendConnEvent(addr, sn, index, false)
	}
	return
}

// 在客户端连接池中找到没有占用的位置
func (c *TcpServer) findFreeIndex() (idx int) {
	idx = -1
	for i := 0; i < c.maxConn; i++ {
		if c.clientList[i].Conn == nil {
			idx = i
			return
		}
	}
	return
}
